home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 / MACD 5.bin / workbench / boot / czesc_2 / saferpatches / source.lha / Source / SaferPatches.c < prev    next >
C/C++ Source or Header  |  1992-10-04  |  11KB  |  281 lines

  1. /**************************************************************************/
  2. /* Discription:                               */
  3. /*  The exec.library SetFunction function is very unsafe to use when      */
  4. /*  more than one program changes a function in a library.          */
  5. /*                                      */
  6. /*  The programs must change the function back in reverse order.      */
  7. /*                                      */
  8. /*  example:                                  */
  9. /*   Two different programs (A & B) changes the DisplayBeep function      */
  10. /*   in intuition.library.                          */
  11. /*                                      */
  12. /*-------------  First both programs changes the function ----------------*/
  13. /*   A: A_OldFunc = SetFunction(IntuitionBase,_LVODisplayBeep,A_DispBeep);*/
  14. /*     A_OldFunc will contain the original position of DisplayBeep.      */
  15. /*                                      */
  16. /*   B: B_OldFunc SetFunction(IntuitionBase,_LVODisplayBeep,B_DispBeep);  */
  17. /*     B_OldFunc will contain the position of A_DispBeep.          */
  18. /*                                      */
  19. /*----    Then both programs restores the function (In wrong order)---------*/
  20. /*   A: SetFunction(IntuitionBase, _LVODisplayBeep; A_OldFunc)            */
  21. /*     The original DisplayBeep function will be restored.          */
  22. /*     (B_DispBeep will not be called)                                  */
  23. /*                                      */
  24. /*   B: SetFunction(IntuitionBase, _LVODisplayBeep; B_OldFunc)            */
  25. /*     The function A_DispBeep will be started again.           */
  26. /*     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~              */
  27. /*     (If program A is no longer present the guru comes when           */
  28. /*      someone calls the DisplayBeep function.)              */
  29. /*                                      */
  30. /*  This program fixes these problems in a fully tranparent way       */
  31. /*                                      */
  32. /**************************************************************************/
  33.  
  34.  
  35. /**************************************************************************/
  36. /*  LibHeader                                  */
  37. /*     NextLib:  Next library in a linked list.               */
  38. /*     LibBase:  Pointer to the libraries base (e.g. intuitionbase).      */
  39. /*     Patches:  Pointer to linked list of patches made to this library.  */
  40. /**************************************************************************/
  41. struct LibHeader {
  42.   struct Library    *LibBase;
  43.   struct Patches    *Patches;
  44.   struct LibHeader  *NextLib;
  45. };
  46.  
  47. /************************************************************************/
  48. /*  Patches                                */
  49. /*     JMP    : Opcode for JMP (used to call the old function).       */
  50. /*     OldFunc    : Address to the previus function (before SetFunction). */
  51. /*     NewFunc    : The new function.                    */
  52. /*     Offset    : Offset in library (Must be negativ).                  */
  53. /*     NextPatch: Pointer to next patch in list.            */
  54. /*                                    */
  55. /*  The first Patch in the library list is just a dummy,        */
  56. /*  Offset = MAGIC_OFFSET (makes the code more simple).                 */
  57. /*  After the dummy comes all patches made to this library sorted after */
  58. /*  their Offset (lowest value first). If there are more then one patch */
  59. /*  at one offset, the most recent comes first.             */
  60. /************************************************************************/
  61. struct Patches {
  62.   USHORT      JMP;
  63.   LONG          OldFunc;
  64.   LONG          NewFunc;
  65.   SHORT       Offset;
  66.   struct Patches *NextPatch;
  67. };
  68. /******* Some useful defines ********/
  69.   /* This offset identifies our dummy patch */
  70. #define MAGIC_OFFSET      123
  71.   /* Kickstart library versions */
  72. #define KS13  35
  73.   /*************/
  74. #define AND &&
  75. #define OR ||
  76.  
  77. /************* Functions ****************/
  78.        /*            A0            A1             D0     */
  79. STATIC LONG  NewSetFunction(APTR Offset, struct Library *Library, LONG NewFunc);
  80. extern LONG  OldSetFunction(APTR Offset, struct Library *Library, LONG NewFunc);
  81.  
  82.        struct LibHeader *MakeHead(struct Library *Library);
  83. STATIC struct Patches    *MakePatch(APTR Offset, struct Patches *Next, LONG NewFunc);
  84.  
  85. /************* Global variables **********/
  86. extern struct DosBase *DOSBase;          /* Must be first */
  87. extern struct SignalSemaphore SetFuncSemaphore;
  88. extern struct LibHeader *MainHeader;
  89.  
  90. extern __fptr  OldSetFuncPtr;
  91.  
  92. /*************************************************/
  93. /* NewSetFunction: Replaces the exec SetFunction */
  94. /*************************************************/
  95. LONG NewSetFunction(APTR Offset, struct Library *Library, LONG NewFunc)         /* D0 */
  96. {
  97.   struct LibHeader *HeadPtr, *HeadPtr1;
  98.   struct Patches *Patch;
  99.   LONG    OldFunc = NULL;
  100.  
  101.   geta4();
  102.  
  103.   /* old dos.library can't be handled here */
  104.   if (Library == DOSBase  AND  Library->lib_Version <= KS13)
  105.     return OldSetFunction(Offset, Library, NewFunc);
  106.  
  107.   /* Be sure no one else is using the patch list */
  108.   ObtainSemaphore(&SetFuncSemaphore);
  109.  
  110.   HeadPtr = MainHeader;
  111.  
  112.   while (HeadPtr1 = HeadPtr->NextLib) {
  113.     /************************/
  114.     /* Find the library     */
  115.     /************************/
  116.  
  117.     if (HeadPtr1->LibBase == Library) {
  118.       Patch = HeadPtr1->Patches;
  119.  
  120.       FOREVER { /* We leave this loop with goto */
  121.     /*******************************************/
  122.     /* Look through the sorted list of patches */
  123.     /*******************************************/
  124.     struct Patches *Patch1 = Patch->NextPatch;
  125.  
  126.     if (Patch1 == NULL OR Patch1->Offset < (WORD)Offset) {
  127.       /****************************************/
  128.       /* No patch at this offset is installed */
  129.       /* Make a new one.              */
  130.       /****************************************/
  131.       Patch1 = MakePatch(Offset, Patch1, NewFunc);
  132.       if (Patch1)
  133.         if (Patch1->OldFunc = OldSetFunction(Offset, Library, NewFunc))
  134.           OldFunc = (LONG)(Patch->NextPatch = Patch1);
  135.         else /* SetFunction failed */
  136.           FreeMem(Patch1,sizeof(struct Patches));
  137.       goto Done;            /******************************/
  138.     }
  139.  
  140.     if (Patch1->Offset == (WORD)Offset) {
  141.       /***************************************/
  142.       /* There are patches already installed */
  143.       /* Find out if anyone is to be removed */
  144.       /***************************************/
  145.       struct Patches *Patch2;
  146.  
  147.       /********************************************************/
  148.       /* Some tasks don't care about the data returned from   */
  149.       /* SetFunction (e.g. Xoper), instead they look directly */
  150.       /* into library structure to find the old function.      */
  151.       /* Since this is bad programming we can't do much about */
  152.       /* it.  If we are lucky no other patches are made to      */
  153.       /* the same offset.                      */
  154.       /********************************************************/
  155.       if ((LONG)Patch1 == NewFunc OR Patch1->OldFunc == NewFunc) {
  156.         /*******************************************************/
  157.         /* User want's to remove the last (or only) made patch */
  158.         /* This is easy, just remove it               */
  159.         /*******************************************************/
  160.         OldFunc = OldSetFunction(Offset, Library, Patch1->OldFunc);
  161.         if (OldFunc == Patch1->NewFunc) {
  162.           Patch->NextPatch = Patch1->NextPatch;
  163.           FreeMem(Patch1,sizeof(struct Patches));
  164.         }
  165.         else {
  166.           /******************************************************/
  167.           /* If we gets here something is very wrong        */
  168.           /* Either has someone managed to change the vector    */
  169.           /* from the outside (Virus !?) or SetFunction failed  */
  170.           /* for some strange reason.                */
  171.           /* We just restore the vector and hopes for the best. */
  172.           /******************************************************/
  173.           if (OldFunc) {
  174.         OldSetFunction(Offset, Library, OldFunc);
  175.         OldFunc = NULL;
  176.           }
  177.           goto Done;
  178.         }
  179.  
  180.         /**************************************************/
  181.         /* If this was the last patch made to the library */
  182.         /* Release unused memory.                  */
  183.         /**************************************************/
  184.         if (Patch->Offset == MAGIC_OFFSET AND
  185.         Patch->NextPatch == NULL) {
  186.           HeadPtr->NextLib = HeadPtr1->NextLib;
  187.           FreeMem(Patch,sizeof(struct Patches));
  188.           FreeMem(HeadPtr1,sizeof(struct LibHeader));
  189.         }
  190.         goto Done;            /******************************/
  191.       }
  192.  
  193.       /********************************************************/
  194.       /* Are there any more patches made to the same offset ? */
  195.       /********************************************************/
  196.       while ((Patch2 = Patch1->NextPatch)  AND
  197.          Patch2->Offset == (WORD)Offset) {
  198.         if ((LONG)Patch2 == NewFunc OR Patch2->OldFunc == NewFunc) {
  199.           /*****************************************************/
  200.           /* The user want's to remove an older patched        */
  201.           /* This is more tricky, must restore OldFunc pointer */
  202.           /*****************************************************/
  203.           Patch1->NextPatch = Patch2->NextPatch;
  204.           Patch1->OldFunc = Patch2->OldFunc;
  205.           OldFunc = Patch2->NewFunc;  /* No SetFunction here !! */
  206.           FreeMem(Patch2,sizeof(struct Patches));
  207.           goto Done;        /******************************/
  208.         }
  209.         Patch1 = Patch2;
  210.       }
  211.       /*****************************************/
  212.       /* This was a new patch which takes over */
  213.       /*****************************************/
  214.       Patch1 = MakePatch(Offset, Patch->NextPatch, NewFunc);
  215.       if (Patch1)
  216.         if (Patch1->OldFunc = OldSetFunction(Offset, Library, NewFunc))
  217.           OldFunc = (LONG)(Patch->NextPatch = Patch1);
  218.         else  /* SetFunction failed */
  219.           FreeMem(Patch1,sizeof(struct Patches));
  220.       goto Done;            /******************************/
  221.     } /* if (Patch1->Offset == ... */
  222.     /* Try next patch in list */
  223.     Patch = Patch1;
  224.       } /* FOREVER */
  225.     } /* if (HeadPtr->Lib ... */
  226.     /* try next library in list */
  227.     HeadPtr = HeadPtr1;
  228.   } /* while (HeadPtr1 = ... */
  229.  
  230.   /***************/
  231.   /* New library */
  232.   /***************/
  233.   HeadPtr1 = HeadPtr->NextLib = MakeHead(Library);
  234.  
  235.   /*******************/
  236.   /* Crete the patch */
  237.   /*******************/
  238.   if (HeadPtr1) {
  239.     if (Patch = MakePatch(Offset, NULL, NewFunc)) {
  240.       /* crete a dummy patch */
  241.       if (HeadPtr1->Patches = MakePatch((APTR)MAGIC_OFFSET, Patch, NULL)) {
  242.     if (Patch->OldFunc = OldSetFunction(Offset, Library, NewFunc)) {
  243.       HeadPtr->NextLib = HeadPtr1;
  244.       OldFunc = (LONG)Patch;
  245.       goto Done;
  246.     } /* SetFunction failed */
  247.     FreeMem(HeadPtr1->Patches,sizeof(struct Patches));
  248.       } /* Can't crete dummy patch */
  249.       FreeMem(Patch,sizeof(struct Patches));
  250.     } /* Can't crete real patch */
  251.     FreeMem(HeadPtr1,sizeof(struct LibHeader));
  252.   } /* Can't crete header */
  253.  
  254. Done:
  255.   ReleaseSemaphore(&SetFuncSemaphore);
  256.  
  257.   return OldFunc;
  258. }
  259.  
  260. struct LibHeader *MakeHead(struct Library *Library)
  261. {
  262.   struct LibHeader *Head;
  263.  
  264.   if (Head = AllocMem(sizeof(struct LibHeader),MEMF_CLEAR))
  265.     Head->LibBase = Library;
  266.   return Head;
  267. }
  268.  
  269. struct Patches *MakePatch(APTR Offset, struct Patches *Next, LONG NewFunc)
  270. {
  271.   struct Patches *Patch;
  272.  
  273.   if (Patch = AllocMem(sizeof(struct Patches),MEMF_CLEAR)) {
  274.     Patch->JMP = 0x4ef9; /* JMP opcode */
  275.     Patch->NewFunc = NewFunc;
  276.     Patch->Offset = (WORD)Offset;
  277.     Patch->NextPatch = Next;
  278.   }
  279.   return Patch;
  280. }
  281.